import caurina.transitions.Tweener;
import caurina.transitions.Equations;
import flash.display.Sprite;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.filters.DropShadowFilter;
// import charts.Elements.Element;
import hxjson2.JSON;
import string.Utils;
import string.Css;
import Object_helper;
import charts.series.HasTooltip;

class Tooltip extends Sprite {
	// JSON style:
	var style:Dynamic;
	
	var tip_style:Float;
	var cached_elements:Array<Dynamic>;
	var tip_showing:Bool;
	
	public var tip_text:String;

	// TODO
	// - figure out why this is broken, even if you change it into a Float
	//   => 26: characters 42-43 : Float should be Int	
	inline public static var CLOSEST:Int = 0;
	inline public static var PROXIMITY:Int = 1;
	inline public static var NORMAL:Int = 2;		// normal tooltip (ugh -- boring!!)

/*
	inline public static var CLOSEST:Float = 0;
	inline public static var PROXIMITY:Float = 1;
	inline public static var NORMAL:Float = 2;		// normal tooltip (ugh -- boring!!)
*/
	
	public function new(json:Dynamic) {
		//
		// we don't want mouseOver events for the
		// tooltip or any children (the text fields)
		//
		this.mouseEnabled = false;
		this.tip_showing = false;
		
		this.style = {
			shadow:		true,
			rounded:	6,
			stroke:		2,
			colour:		'#808080',
			background:	'#f0f0f0',
			title:		"color: #0000F0; font-weight: bold; font-size: 12;",
			body:		"color: #000000; font-weight: normal; font-size: 12;",
			mouse:		Tooltip.CLOSEST,
			text:		"_default"
		};

		if( json )
		{
			this.style = Object_helper.merge( json, this.style );
		}

			
		this.style.colour = Utils.get_colour( this.style.colour );
		this.style.background = Utils.get_colour( this.style.background );
		this.style.title = new Css( this.style.title );
		this.style.body = new Css( this.style.body );
		
		this.tip_style = this.style.mouse;
		this.tip_text = this.style.text;
		this.cached_elements = [];
		
		if( this.style.shadow==1 )
		{
			var dropShadow:DropShadowFilter = new flash.filters.DropShadowFilter();
			dropShadow.blurX = 4;
			dropShadow.blurY = 4;
			dropShadow.distance = 4;
			dropShadow.angle = 45;
			dropShadow.quality = 2;
			dropShadow.alpha = 0.5;
			// apply shadow filter
			this.filters = [dropShadow];
		}

		super();
	}
	
	public function make_tip( elements:Array<Dynamic> ):Void {
		
		this.graphics.clear();
		
		while( this.numChildren > 0 )
			this.removeChildAt(0);

		var height:Float = 0;
		var x:Int = 5;
		
		for ( e in elements ) {
			
			var o:Dynamic = this.make_one_tip(e, x);
			height = Math.max(height, o.height);
			x += o.width + 2;
		}
		
		this.graphics.lineStyle(this.style.stroke, this.style.colour, 1);
		this.graphics.beginFill(this.style.background, 1);
	
		this.graphics.drawRoundRect(
			0,0,
			width+10, height + 5,
			this.style.rounded, this.style.rounded );
	}
		
	function make_one_tip( e:HasTooltip, x:Float ):Dynamic {
		
		var tt:String = e.get_tooltip();
		var lines:Array<Dynamic> = tt.split( '<br>' );
		
		var top:Float = 5;
		var width:Float = 0;
		
		if ( lines.length > 1 ) {
			
			var title:TextField = this.make_title(lines.shift());
			title.mouseEnabled = false;
			title.x = x;
			title.y = top;
			top += title.height;
			width = title.width;
			
			this.addChild( title );
		}
		
		var text:TextField = this.make_body(lines.join( '\n' ));
		text.mouseEnabled = false;
		text.x = x;
		text.y = top;
		width = Math.max( width, text.width );
		this.addChild( text );
		
		top += text.height;
		return {width:width, height:top};
	}

	function make_title( text:String ):TextField {
		
		var title:TextField = new TextField();
		title.mouseEnabled = false;
		
		title.htmlText =  text;
		/*
			* 
			* Start thinking about just using html formatting 
			* instead of text format below.  We could do away
			* with the title textbox entirely and let the user
			* use:
			* <b>title stuff</b><br>Here is the value
			* 
			*/
		var format:TextFormat = new TextFormat();
		format.color = this.style.title.color;
		format.font = "Verdana";
		format.bold = (this.style.title.font_weight=="bold");
		format.size = this.style.title.font_size;
		format.align = flash.text.TextFormatAlign.RIGHT;//"right";
		title.setTextFormat(format);
		title.autoSize = flash.text.TextFieldAutoSize.LEFT; // "left";
		
		return title;
	}			
		
	function make_body( body:String ):TextField {
		
		var text:TextField = new TextField();
		text.mouseEnabled = false;
		
		text.htmlText =  body;
		var format2:TextFormat = new TextFormat();
		format2.color = this.style.body.color;
		format2.font = "Verdana";
		format2.bold = (this.style.body.font_weight=="bold");
		format2.size = this.style.body.font_size;
		format2.align = flash.text.TextFormatAlign.LEFT; //"left";
		text.setTextFormat(format2);
		text.autoSize = flash.text.TextFieldAutoSize.LEFT; //"left";
		
		return text;
	}
	
	function get_pos( e:HasTooltip ):flash.geom.Point {

		var pos:Dynamic = e.get_tip_pos();

		var x:Float = (pos.x + this.width + 16) > this.stage.stageWidth ? (this.stage.stageWidth - this.width - 16) : pos.x;
		
		var y:Float = pos.y;
		y -= 4;
		y -= (this.height + 10 ); // 10 == border size
		
		if( y < 0 )
		{
			// the tooltip has drifted off the top of the screen, move it down:
			y = 0;
		}
		return new flash.geom.Point(x, y);
	}
	
	function show_tip( e:HasTooltip ):Void {
		
		// remove the 'hide' tween
		Tweener.removeTweens( this );
		var p:flash.geom.Point = this.get_pos( e );
		
		if ( this.style.mouse == Tooltip.CLOSEST )
		{
			//
			// make the tooltip appear (if invisible)
			// and shoot to the correct position
			//
			this.visible = true;
			this.alpha = 1;
			this.x = p.x;
			this.y = p.y;
		}
		else
		{
			// make the tooltip fade in gently
			this.tip_showing = true;
				
			trace('show');
			this.alpha = 0;
			this.visible = true;
			this.x = p.x;
			this.y = p.y;
			Tweener.addTween(
				this,
				{
					alpha:1,
					time:0.4,
					transition:Equations.easeOutExpo
				} );
		}
	}
	
	public function draw( e:HasTooltip ):Void {

		if ( this.cached_elements[0] == e )
		{
			// if the tip is showing, don't make it 
			// show again because this makes it flicker
			if( !this.tip_showing )
				this.show_tip(e);
		}
		else
		{

			// this is a new tooltip, tell
			// the old highlighted item to
			// return to ground state
			this.untip();
			
			// get the new text and recreate it
			this.cached_elements = [e];
			
			this.make_tip( [e] );
			this.show_tip(e);
		}
	}
	
	public function closest( elements:Array<Dynamic> ):Void {

		if( elements.length == 0 )
			return;
		
		if( this.is_cached( elements ) )
			return;
		
		this.untip();
		this.cached_elements = elements;
		this.tip();

		//
		//trace( 'make new tooltip' );
		//trace( Math.random() );
		//
		
		this.make_tip( elements );

		var p:flash.geom.Point = this.get_pos( elements[0] );
		
		this.visible = true;
		
		Tweener.addTween(this, { x:p.x, time:0.3, transition:Equations.easeOutExpo } );
		Tweener.addTween(this, { y:p.y, time:0.3, transition:Equations.easeOutExpo } );
	}
	
	//
	// TODO: if elements has 1 item and cached_elements has 2
	//       one of which is in elements, this function
	//       returns true which is wrong
	//
	function is_cached( elements:Array<Dynamic> ):Bool {
		
		if ( this.cached_elements.length == 0 )
			return false;
			
		for (e in elements )
			if ( this.cached_elements.indexOf(e) == -1 )
				return false;
				
		return true;
	}
	
	function untip():Void {
		for (e in this.cached_elements )
			e.set_tip( false );
	}
	
	function tip():Void {
		for (e in this.cached_elements )
			e.set_tip( true );
	}
	
	function hideAway() : Void {
		this.visible = false;
		this.untip();
		this.cached_elements = new Array();
		this.alpha = 1;
	}
	
	public function hide():Void {
		this.tip_showing = false;
		trace('hide tooltip');
		Tweener.addTween(this, { alpha:0, time:0.6, transition:Equations.easeOutExpo, onComplete:hideAway } );
	}
	
	public function get_tip_style():Float {
		return this.tip_style;
	}

	public function set_tip_style( i:Float ):Void {
		this.tip_style = i;
	}
	
	public function die():Void {
		
		this.filters = [];
		this.graphics.clear();
		
		while( this.numChildren > 0 )
			this.removeChildAt(0);
	
		this.style = null;
		this.cached_elements = null;
	}
}
